package top.continew.wechat.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import top.continew.wechat.common.core.ResultCode;
import top.continew.wechat.common.exception.BusinessException;
import top.continew.wechat.common.core.Result;
import top.continew.wechat.user.dto.UserLoginDTO;
import top.continew.wechat.user.dto.UserPasswordDTO;
import top.continew.wechat.user.dto.UserRegisterDTO;
import top.continew.wechat.user.dto.UserUpdateDTO;
import top.continew.wechat.user.entity.UserEntity;
import top.continew.wechat.user.mapper.UserMapper;
import top.continew.wechat.user.service.UserService;
import top.continew.wechat.user.util.JwtUtil;
import top.continew.wechat.user.util.UserContextUtil;
import top.continew.wechat.user.vo.UserLoginVO;
import top.continew.wechat.user.vo.UserVO;

import java.time.LocalDateTime;
import java.util.Objects;

/**
 * 用户服务实现类
 */
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, UserEntity> implements UserService {

    private final JwtUtil jwtUtil;
    private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    
    // 登录失败次数限制
    private static final int MAX_LOGIN_FAIL_TIMES = 5;
    private static final long LOGIN_FAIL_LOCK_TIME = 30 * 60 * 1000; // 30分钟，单位：毫秒
    private static final Map<String, AtomicInteger> loginFailCountMap = new ConcurrentHashMap<>();
    private static final Map<String, Long> loginLockTimeMap = new ConcurrentHashMap<>();

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> register(UserRegisterDTO userRegisterDTO) {
        // 1. 验证两次密码是否一致
        if (!Objects.equals(userRegisterDTO.getPassword(), userRegisterDTO.getConfirmPassword())) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "两次密码不一致");
        }

        // 2. 验证密码强度
        if (userRegisterDTO.getPassword().length() < 8) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "密码长度不能少于8位");
        }

        // 3. 验证用户名是否已存在
        if (this.lambdaQuery()
                .eq(UserEntity::getUsername, userRegisterDTO.getUsername())
                .exists()) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "用户名已存在");
        }

        // 4. 验证手机号是否已存在
        if (StringUtils.isNotBlank(userRegisterDTO.getPhone()) && 
            this.lambdaQuery()
                .eq(UserEntity::getPhone, userRegisterDTO.getPhone())
                .exists()) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "手机号已存在");
        }

        // 5. 验证邮箱是否已存在
        if (StringUtils.isNotBlank(userRegisterDTO.getEmail()) && 
            this.lambdaQuery()
                .eq(UserEntity::getEmail, userRegisterDTO.getEmail())
                .exists()) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "邮箱已存在");
        }

        // 6. 创建用户实体
        UserEntity userEntity = new UserEntity();
        BeanUtils.copyProperties(userRegisterDTO, userEntity);
        // 密码加密
        userEntity.setPassword(passwordEncoder.encode(userRegisterDTO.getPassword()));
        // 设置默认值
        userEntity.setStatus(1);
        userEntity.setGender(0);
        userEntity.setAvatar("https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif");
        userEntity.setCreateTime(LocalDateTime.now());
        userEntity.setUpdateTime(LocalDateTime.now());

        // 7. 保存用户
        this.save(userEntity);

        return Result.success();
    }

    @Override
    public Result<UserLoginVO> login(UserLoginDTO userLoginDTO) {
        String username = userLoginDTO.getUsername();
        
        // 1. 检查用户是否被锁定
        Long lockTime = loginLockTimeMap.get(username);
        if (lockTime != null) {
            long currentTime = System.currentTimeMillis();
            if (currentTime < lockTime) {
                long remainingMinutes = (lockTime - currentTime) / (60 * 1000);
                throw new BusinessException(ResultCode.PARAM_ERROR, 
                    "账户已被锁定，请" + remainingMinutes + "分钟后再试");
            } else {
                // 锁定时间已过，清除锁定记录
                loginLockTimeMap.remove(username);
                loginFailCountMap.remove(username);
            }
        }
        
        try {
            // 2. 查询用户
            UserEntity userEntity = this.lambdaQuery()
                .eq(UserEntity::getUsername, username)
                .one();

            // 3. 验证用户是否存在
            if (userEntity == null) {
                recordLoginFailure(username);
                throw new BusinessException(ResultCode.PARAM_ERROR, "用户名或密码错误");
            }

            // 4. 验证密码是否正确
            if (!passwordEncoder.matches(userLoginDTO.getPassword(), userEntity.getPassword())) {
                recordLoginFailure(username);
                throw new BusinessException(ResultCode.PARAM_ERROR, "用户名或密码错误");
            }

            // 5. 验证用户状态
            if (userEntity.getStatus() != 1) {
                throw new BusinessException(ResultCode.PARAM_ERROR, "账号已被禁用");
            }

            // 6. 登录成功，清除失败记录
            loginFailCountMap.remove(username);
            loginLockTimeMap.remove(username);

            // 7. 更新最后登录时间
            userEntity.setLastLoginTime(LocalDateTime.now());
            this.updateById(userEntity);

            // 8. 生成token
            String token = jwtUtil.generateToken(userEntity.getId());

            // 9. 构建返回结果
            UserLoginVO userLoginVO = new UserLoginVO();
            userLoginVO.setToken(token);
            userLoginVO.setExpiresIn(86400L);

            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(userEntity, userVO);
            userLoginVO.setUser(userVO);

            return Result.success(userLoginVO);
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            recordLoginFailure(username);
            throw new BusinessException(ResultCode.SYSTEM_ERROR, "登录失败，请稍后再试");
        }
    }
    
    /**
     * 记录登录失败次数，并在达到最大失败次数时锁定账户
     *
     * @param username 用户名
     */
    private void recordLoginFailure(String username) {
        AtomicInteger failCount = loginFailCountMap.computeIfAbsent(username, k -> new AtomicInteger(0));
        int currentFailCount = failCount.incrementAndGet();
        
        if (currentFailCount >= MAX_LOGIN_FAIL_TIMES) {
            // 锁定账户
            loginLockTimeMap.put(username, System.currentTimeMillis() + LOGIN_FAIL_LOCK_TIME);
            throw new BusinessException(ResultCode.PARAM_ERROR, 
                "登录失败次数过多，账户已被锁定30分钟");
        } else {
            int remainingAttempts = MAX_LOGIN_FAIL_TIMES - currentFailCount;
            throw new BusinessException(ResultCode.PARAM_ERROR, 
                "用户名或密码错误，还有" + remainingAttempts + "次尝试机会");
        }
    }

    @Override
    public Result<UserVO> getCurrentUser() {
        // 获取当前登录用户ID
        Long userId = UserContextUtil.getCurrentUserId();
        if (userId == null) {
            throw new BusinessException(ResultCode.UNAUTHORIZED, "用户未登录");
        }

        // 查询用户信息
        UserEntity userEntity = this.getById(userId);
        if (userEntity == null) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "用户不存在");
        }

        // 构建返回结果
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(userEntity, userVO);

        return Result.success(userVO);
    }

    @Override
    public Result<UserVO> getUserById(Long userId) {
        // 查询用户信息
        UserEntity userEntity = this.getById(userId);
        if (userEntity == null) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "用户不存在");
        }

        // 构建返回结果
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(userEntity, userVO);

        return Result.success(userVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> updateUser(UserUpdateDTO userUpdateDTO) {
        // 获取当前登录用户ID
        Long userId = UserContextUtil.getCurrentUserId();
        if (userId == null) {
            throw new BusinessException(ResultCode.UNAUTHORIZED, "用户未登录");
        }

        // 查询用户信息
        UserEntity userEntity = this.getById(userId);
        if (userEntity == null) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "用户不存在");
        }

        // 验证手机号是否已存在
        if (userUpdateDTO.getPhone() != null && !userUpdateDTO.getPhone().isEmpty() 
                && !Objects.equals(userEntity.getPhone(), userUpdateDTO.getPhone())) {
            LambdaQueryWrapper<UserEntity> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(UserEntity::getPhone, userUpdateDTO.getPhone());
            if (this.count(queryWrapper) > 0) {
                throw new BusinessException(ResultCode.PARAM_ERROR, "手机号已存在");
            }
        }

        // 验证邮箱是否已存在
        if (userUpdateDTO.getEmail() != null && !userUpdateDTO.getEmail().isEmpty() 
                && !Objects.equals(userEntity.getEmail(), userUpdateDTO.getEmail())) {
            LambdaQueryWrapper<UserEntity> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(UserEntity::getEmail, userUpdateDTO.getEmail());
            if (this.count(queryWrapper) > 0) {
                throw new BusinessException(ResultCode.PARAM_ERROR, "邮箱已存在");
            }
        }

        // 更新用户信息
        BeanUtils.copyProperties(userUpdateDTO, userEntity);
        userEntity.setUpdateTime(LocalDateTime.now());
        this.updateById(userEntity);

        return Result.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Void> updatePassword(UserPasswordDTO userPasswordDTO) {
        // 获取当前登录用户ID
        Long userId = UserContextUtil.getCurrentUserId();
        if (userId == null) {
            throw new BusinessException(ResultCode.UNAUTHORIZED, "用户未登录");
        }

        // 查询用户信息
        UserEntity userEntity = this.getById(userId);
        if (userEntity == null) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "用户不存在");
        }

        // 验证旧密码是否正确
        if (!passwordEncoder.matches(userPasswordDTO.getOldPassword(), userEntity.getPassword())) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "旧密码错误");
        }

        // 验证两次密码是否一致
        if (!Objects.equals(userPasswordDTO.getNewPassword(), userPasswordDTO.getConfirmPassword())) {
            throw new BusinessException(ResultCode.PARAM_ERROR, "两次密码不一致");
        }

        // 更新密码
        userEntity.setPassword(passwordEncoder.encode(userPasswordDTO.getNewPassword()));
        userEntity.setUpdateTime(LocalDateTime.now());
        this.updateById(userEntity);

        return Result.success();
    }

    @Override
    public Result<Void> logout() {
        // 由于使用JWT，服务端不需要做任何处理，客户端删除token即可
        return Result.success();
    }
}
